﻿using System.Threading.Tasks;

using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;

using ProjectTaskManager.Application.Contracts;

using Volo.Abp.Application.Services;
using Volo.Abp.Identity;

using IdentityUser = Volo.Abp.Identity.IdentityUser;
using SignInResult = Microsoft.AspNetCore.Identity.SignInResult;

namespace ProjectTaskManager.Application
{
    public class AccountAppService : ApplicationService, IAccountAppService
    {
        private readonly IOptions<IdentityOptions> _identityOptions;

        private SignInManager<IdentityUser> SignInManager => LazyServiceProvider.LazyGetRequiredService<SignInManager<IdentityUser>>();
        private IdentitySecurityLogManager IdentitySecurityLogManager => LazyServiceProvider.LazyGetRequiredService<IdentitySecurityLogManager>();
        private IdentityUserManager IdentityUserManager => LazyServiceProvider.LazyGetRequiredService<IdentityUserManager>();
        private IIdentityUserRepository IdentityUserRepository => LazyServiceProvider.LazyGetRequiredService<IIdentityUserRepository>();
        private ILookupNormalizer LookupNormalizer => LazyServiceProvider.LazyGetRequiredService<ILookupNormalizer>();

        public AccountAppService(IOptions<IdentityOptions> identityOptions)
        {
            _identityOptions = identityOptions;
        }

        public async Task<SignInResult> LoginAsync(string userName, string password)
        {
            var signInResult = await SignInManager.PasswordSignInAsync(
                userName,
                password,
                true,
                true
            );
            return signInResult;
        }

        [HttpGet]
        public async Task LogoutAsync()
        {
            await IdentitySecurityLogManager.SaveAsync(new IdentitySecurityLogContext()
            {
                Identity = IdentitySecurityLogIdentityConsts.Identity,
                Action = IdentitySecurityLogActionConsts.Logout
            });

            await SignInManager.SignOutAsync();
        }

        public async Task<IdentityResult> ChangePasswordAsync(string userName, string oldPassword, string password)
        {
            var user = await IdentityUserRepository.FindByNormalizedUserNameAsync(LookupNormalizer.NormalizeName(userName));

            return await IdentityUserManager.ChangePasswordAsync(user, oldPassword, password);
        }

        public virtual async Task<IdentityUserDto> RegisterAsync(RegisterDto input)
        {
            await _identityOptions.SetAsync();

            var user = new IdentityUser(GuidGenerator.Create(), input.UserName, input.EmailAddress, CurrentTenant.Id);

            var identityResult = await IdentityUserManager.CreateAsync(user, input.Password);
            identityResult.CheckErrors();

            await IdentityUserManager.SetEmailAsync(user, input.EmailAddress);
            await IdentityUserManager.AddDefaultRolesAsync(user);

            return ObjectMapper.Map<IdentityUser, IdentityUserDto>(user);
        }
    }
}